//go:build windows
// +build windows

package wake

/*
#cgo CFLAGS: -I${SRCDIR}/../../c/include
#cgo windows LDFLAGS: -L${SRCDIR}/../../c/libs -lmsc_x64 -lwinmm
#include <stdlib.h>
#include "stdio.h"
#include <string.h>
#include <windows.h>
#include "msp_cmn.h"
#include "qivw.h"
#include "msp_errors.h"

extern int go_ivw_callback(char *sessionID, int msg, int param1, int param2, void *info, void *userData);

static int c_ivw_callback(const char *sessionID, int msg, int param1, int param2, const void *info, void *userData) {
    return go_ivw_callback((char*)sessionID, msg, param1, param2, (void*)info, userData);
}

static HANDLE wait_event = NULL;
static HWAVEIN h_wavein = NULL;
static WAVEFORMATEX wavfmt = {0};

#define FRAME_LEN 640
#define BUFFER_SIZE (1024 * 500)

static WAVEHDR wave_hdr = {0};
static char* audio_buffer = NULL;

static int start_microphone() {
    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
    wavfmt.nSamplesPerSec = 16000;
    wavfmt.wBitsPerSample = 16;
    wavfmt.nChannels = 1;
    wavfmt.nAvgBytesPerSec = 16000 * 2;
    wavfmt.nBlockAlign = 2;
    wavfmt.cbSize = 0;

    wait_event = CreateEvent(NULL, 0, 0, NULL);
    if (!wait_event) return -1;

    if (waveInOpen(&h_wavein, WAVE_MAPPER, &wavfmt, (DWORD_PTR)wait_event, 0L, CALLBACK_EVENT) != MMSYSERR_NOERROR) {
        CloseHandle(wait_event);
        return -2;
    }

    audio_buffer = (char*)malloc(BUFFER_SIZE);
    if (!audio_buffer) {
        waveInClose(h_wavein);
        CloseHandle(wait_event);
        return -3;
    }

    wave_hdr.lpData = audio_buffer;
    wave_hdr.dwBufferLength = BUFFER_SIZE;
    wave_hdr.dwFlags = 0;
    wave_hdr.dwLoops = 1;

    if (waveInPrepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
        free(audio_buffer);
        waveInClose(h_wavein);
        CloseHandle(wait_event);
        return -4;
    }

    if (waveInAddBuffer(h_wavein, &wave_hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
        waveInUnprepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR));
        free(audio_buffer);
        waveInClose(h_wavein);
        CloseHandle(wait_event);
        return -5;
    }

    if (waveInStart(h_wavein) != MMSYSERR_NOERROR) {
        waveInUnprepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR));
        free(audio_buffer);
        waveInClose(h_wavein);
        CloseHandle(wait_event);
        return -6;
    }

    return 0;
}

static void stop_microphone() {
    if (h_wavein) {
        waveInStop(h_wavein);
        waveInReset(h_wavein);
        waveInUnprepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR));
        waveInClose(h_wavein);
        h_wavein = NULL;
    }
    if (audio_buffer) {
        free(audio_buffer);
        audio_buffer = NULL;
    }
    if (wait_event) {
        CloseHandle(wait_event);
        wait_event = NULL;
    }
}

static int process_audio(const char* session_id) {
    int err_code = MSP_SUCCESS;
    int audio_stat = MSP_AUDIO_SAMPLE_FIRST;
    long audio_count = 0;

    while (1) {
        Sleep(200);

        // 检查是否需要重置缓冲区
        if (wave_hdr.dwBytesRecorded >= BUFFER_SIZE - FRAME_LEN * 10) {
            // 停止当前录音
            waveInStop(h_wavein);
            
            // 重置缓冲区
            waveInReset(h_wavein);
            waveInUnprepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR));
            
            // 重新初始化缓冲区
            memset(&wave_hdr, 0, sizeof(WAVEHDR));
            wave_hdr.lpData = audio_buffer;
            wave_hdr.dwBufferLength = BUFFER_SIZE;
            wave_hdr.dwFlags = 0;
            wave_hdr.dwLoops = 1;
            
            // 重新准备缓冲区
            if (waveInPrepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
                return -1;
            }
            
            // 重新添加缓冲区
            if (waveInAddBuffer(h_wavein, &wave_hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
                waveInUnprepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR));
                return -1;
            }
            
            // 重新开始录音
            if (waveInStart(h_wavein) != MMSYSERR_NOERROR) {
                waveInUnprepareHeader(h_wavein, &wave_hdr, sizeof(WAVEHDR));
                return -1;
            }

            audio_count = 0;
            continue;
        }

        long len = 10 * FRAME_LEN;
        if (audio_count + len > wave_hdr.dwBytesRecorded) {
            len = wave_hdr.dwBytesRecorded - audio_count;
            if (len <= 0) continue;
        }

        err_code = QIVWAudioWrite(session_id, (const void*)&audio_buffer[audio_count], len, audio_stat);
        if (err_code != MSP_SUCCESS) return err_code;

        audio_count += len;
        audio_stat = MSP_AUDIO_SAMPLE_CONTINUE;
        printf("csid=%s,aus=%d\n", session_id, audio_stat);

    }

    return MSP_SUCCESS;
}

static int start_wake_service_mic() {
	const char *params = "ivw_threshold=0:1450,sst=wakeup,ivw_res_path =fo|res/ivw/wakeupresource.jet";
    int err_code = MSP_SUCCESS;
    const char* session_id = QIVWSessionBegin(NULL, params, &err_code);
    if (err_code != MSP_SUCCESS) return err_code;

    err_code = QIVWRegisterNotify(session_id, c_ivw_callback, NULL);
    if (err_code != MSP_SUCCESS) {
        QIVWSessionEnd(session_id, "error");
        return err_code;
    }

    err_code = start_microphone();
    if (err_code != 0) {
        QIVWSessionEnd(session_id, "error");
        return err_code;
    }

    err_code = process_audio(session_id);
    stop_microphone();

    QIVWSessionEnd(session_id, err_code == MSP_SUCCESS ? "success" : "error");
    return err_code;
}
*/
import "C"
import (
	"fmt"
	"sync"
	"unsafe"
	"time"
)

var (
	wakeupCallback func(string)
	callbackMu     sync.RWMutex
	isRunning      bool
	runningMu      sync.Mutex
)

//export go_ivw_callback
func go_ivw_callback(sessionID *C.char, msg C.int, param1 C.int, param2 C.int, info unsafe.Pointer, userData unsafe.Pointer) C.int {
	if msg == C.MSP_IVW_MSG_WAKEUP {
		fmt.Printf("检测到唤醒词，时间: %v\n", time.Now())
		callbackMu.RLock()
		if wakeupCallback != nil {
			wakeupCallback(C.GoString((*C.char)(info)))
		}
		callbackMu.RUnlock()
	}
	return 0
}

// StartWakeService 启动语音唤醒服务
func StartWakeService(callback func(string)) error {
	runningMu.Lock()
	if isRunning {
		runningMu.Unlock()
		return fmt.Errorf("wake service is already running")
	}
	isRunning = true
	runningMu.Unlock()

	// 设置回调函数
	callbackMu.Lock()
	wakeupCallback = callback
	callbackMu.Unlock()

	// 登录参数
	loginParams := C.CString("appid = 5efaadde, work_dir = .")
	defer C.free(unsafe.Pointer(loginParams))

	// 用户登录
	ret := C.MSPLogin(nil, nil, loginParams)
	if ret != C.MSP_SUCCESS {
		return fmt.Errorf("MSPLogin failed with error code: %d", ret)
	}

	// 启动麦克风唤醒服务
	go func() {
		for isRunning {
			ret := C.start_wake_service_mic()
			if ret != C.MSP_SUCCESS {
				fmt.Printf("Wake service error: %d, time: %v\n", ret, time.Now())
				// 添加一些重试延迟，避免频繁重试
				time.Sleep(2 * time.Second)
			}
		}
	}()

	return nil
}

// StopWakeService 停止语音唤醒服务
func StopWakeService() {
	runningMu.Lock()
	isRunning = false
	runningMu.Unlock()
	
	C.MSPLogout()
}